package org.lanqiao.tjut.practice;

import java.util.Scanner;

import org.junit.Test;

public class Practice1to15 {

	// 【程序0】题目：输入一个年份，判定该年是闰年还是平年。
	// 判定条件：能被400整除的是闰年；能被4整除且不能被100整除的也是闰年。1900不是闰年
	@Test
	public void test00() {
		int yearNum = -1;// 定义一个变量年份
		Scanner input = new Scanner(System.in);
		System.out.println("请输入年份：");// 从控制台输入一个年份
		yearNum = input.nextInt();
		// 判定是否为闰年的条件
		if (yearNum % 400 == 0 | yearNum % 4 == 0 & yearNum % 100 != 0) {
			System.out.println(yearNum + "年是闰年");
		} else {
			System.out.println(yearNum + "年是平年");
		}
	}

	// 【程序1】题目：古典问题：有一对兔子，从出生后第3个月起每个月都生一对兔子，小兔子长到第三个月后每个月又生一对兔子，
	// 假如兔子都不死，问每个月的兔子总数为多少？
	@Test
	public void test01() {
		int[] iNum = new int[24];// 创建一个数组，用来存放每个月的兔子总数
		iNum[0] = iNum[1] = 1;// 前两个月的兔子总数都为1对
		for (int i = 1; i <= 24; i++) {
			if (i < 3) {
				System.out.println("第" + i + "个月兔子总数为：1对");// 输出前两个月的兔子总数
			} else {
				iNum[i - 1] = iNum[i - 2] + iNum[i - 3];// 从第三个月开始，之后每个月的兔子总数
				System.out.println("第" + i + "个月兔子总数为：" + iNum[i - 1] + "对");
			}
		}
	}

	// 递归方法
	@Test
	public void test011() {
		// 定义兔子数量
		int rabbitNum = 0;
		// for循环求第十个月的兔子数量
		for (int i = 1; i <= 10; i++) {
			// 调用求兔子数量的方法
			rabbitNum = getMonthNum(i);
		}
		System.out.println("兔子第10个月的总数为：" + rabbitNum);
	}

	/**
	 * 求兔子数量
	 * 
	 * @param x
	 *            月份
	 * @return 兔子数量
	 */
	public static int getMonthNum(int x) {
		// 定义兔子数量-默认为1
		int initRabbit = 1;
		// 1,2月兔子数量为1
		if (x == 1 || x == 2) {
			return initRabbit;
		}
		// 其他月份为前两个月的数量和，递归
		initRabbit = getMonthNum(x - 1) + getMonthNum(x - 2);
		return initRabbit;
	}

	// 【程序2】题目：判断101-200之间有多少个素数，并输出所有素数。
	// 程序分析：判断素数的方法：用一个数分别去除2到sqrt(这个数)，如果能被整除， 则表明此数不是素数，反之是素数。
	@Test
	public void test02() {
		// 定义一个变量表示素数的总数
		int k = 0;
		// 外层for循环检验101-200之间的数
		for (int i = 101; i < 200; i++) {
			// 检验标志位，默认为true
			boolean isFlag = true;
			// 还可以为：for (int j = 2; j <i; j++)
			// 检验是否为质数
			for (int j = 2; j <= (int) Math.sqrt(i); j++) {
				// 整除
				if (i % j == 0) {
					isFlag = false;
					break;
				}
			}
			if (isFlag) {
				// 素数的个数加1
				k++;
				// 输出每个素数
				System.out.println(i);
			}
		}
		System.out.println("101-120之间有" + k + "个素数");
	}

	// 【程序3】题目：打印出所有的 "水仙花数 "，所谓 "水仙花数 "是指一个三位数，
	// 其各位数字立方和等于该数本身。例如：153是一个 "水仙花数 "，因为153=1的三次方＋5的三次方＋3的三次方。
	@Test
	public void test03() {
		// for循环，表示三位数从100-999
		for (int i = 100; i <= 999; i++) {
			int b = i / 100;// 百位取值
			int s = i / 10 % 10;// 十位取值
			int g = i % 100 % 10;// 个位取值
			// 表示水仙花数的计算
			if (i == b * b * b + s * s * s + g * g * g) {
				System.out.print(" " + i);
			}
		}
	}

	/*
	 * 【程序4】 题目：将一个正整数分解质因数。例如：输入90,打印出90=2*3*3*5。
	 * 程序分析：对n进行分解质因数，应先找到一个最小的质数k，然后按下述步骤完成：
	 * (1)如果这个质数k恰等于n，则说明分解质因数的过程已经结束，打印出即可。
	 * (2)如果n>k，但n能被k整除，则应打印出k的值，并用n除以k的商,作为新的正整数n,重复执行第一步。
	 * (3)如果n不能被k整除，则用k+1作为k的值,重复执行第一步。
	 */
	@Test
	public void test04() {
		Scanner input = new Scanner(System.in);
		System.out.println("请输入一个正整数：");
		// 从控制台获取正整数n
		int n = input.nextInt();
		// for循环确定质因数从2开始依次加1.同时不符合for循环的条件则为步骤一，符合for循环条件则为步骤二、三
		for (int k = 2; k < n; k++) {
			while (k < n) {
				// 步骤二
				if (n % k == 0) {
					// 分解质因数结果
					System.out.print(k + "*");
					// 用n除以k的商,作为新的正整数n
					n = n / k;
				} else {
					// 步骤三
					break;
				}
			}
		}
		// 步骤一中的打印
		System.out.println(n);
	}

	// 【程序5】 题目：利用条件运算符的嵌套来完成此题：
	// 学习成绩> =90分的同学用A表示， 60-89分之间的用B表示，60分以下的用C表示。
	@Test
	public void test05() {
		int iScore = 0;
		Scanner input = new Scanner(System.in);
		System.out.println("请输入该同学的分数：");

		iScore = input.nextInt();
		if (iScore >= 90) {
			System.out.println("该学生成绩为A");
		} else if (iScore >= 60) {
			System.out.println("该学生成绩为B");
		} else if (iScore < 60) {
			System.out.println("该学生成绩为C");
		}
	}

	// 【程序6】 题目：输入两个正整数m和n，求其最大公约数和最小公倍数。
	// 在循环中，只要除数不等于0，用较大数除以较小的数，将小的一个数作为下一轮循环的大数
	// 取得的余数作为下一轮循环的较小的数
	// 如此循环直到较小的数的值为0，返回较大的数， 此数即为最大公约数，最小公倍数为两数之积除以最大公约数
	@Test
	public void test06() {
		// 从控制台输入两个数值
		Scanner input = new Scanner(System.in);
		System.out.println("请输入正整数m:");
		int m = input.nextInt();
		System.out.println("请输入正整数n:");
		int n = input.nextInt();
		// 定义方法的返回值为j
		int j = iExcept(m, n);
		System.out.println("所给两个数的最大公约数为：" + j);
		// 计算最小公倍数
		int k = (m * n) / j;
		System.out.println("所给两个数的最小公倍数为：" + k);
	}

	/**
	 * 计算两个数的最大公约数
	 * 
	 * @param a
	 *            数值a
	 * @param b
	 *            数值b
	 * @return 返回两个数的最大公约数
	 */
	private int iExcept(int a, int b) {
		// 判定a是否大于b，如果不大于 交换a，b的值
		if (a < b) {
			int temp = b;
			b = a;
			a = temp;
		}
		// 如果能够整除，则b即为最大公约数
		if (a % b == 0) {
			return b;
		} else {
			// 如果不能整除则递归调用本身方法，将小的一个数作为下一轮循环的大数，
			// 取得的余数作为下一轮循环的较小的数
			return iExcept(b, a % b);
		}
	}

	// 【程序7】
	// 题目：输入一行字符，分别统计出其中英文字母、空格、数字和其它字符的个数。
	@Test
	public void test07() {
		// 从控制台输入一串字符
		Scanner input = new Scanner(System.in);
		System.out.println("请输入一个字符串:");
		String str = input.nextLine();
		// 定义五个变量:分别表示英文字母，数字，空格，其他字符的个数
		int letterCount = 0;
		int numCount = 0;
		int spaceCount = 0;
		int othersCount = 0;
		// 将输入的字符串转换为一个数组
		char[] arrStr = str.toCharArray();
		// for循环表示依次循环整个字符串
		for (int i = 0; i < arrStr.length; i++) {
			// 判定字符串中英文字母的个数
			if ((arrStr[i] >= 'a' && arrStr[i] < 'z') || (arrStr[i] >= 'A' && arrStr[i] < 'Z')) {
				letterCount++;
				// 判定字符串中数字的个数
			} else if (arrStr[i] >= '0' && arrStr[i] <= '9') {
				numCount++;
				// 判定字符串中空格的个数
			} else if (arrStr[i] == ' ') {
				spaceCount++;
				// 判定字符创其他字符的个数s
			} else {
				othersCount++;
			}
		}
		// 输出结果
		System.out.println("该字符串中,英文字母的个数为：" + letterCount);
		System.out.println("该字符串中,数字的个数为：" + numCount);
		System.out.println("该字符串中,空格的个数为：" + spaceCount);
		System.out.println("该字符串中,其他字符的个数为：" + othersCount);
	}

	// 【程序8】
	// 题目：求s=a+aa+aaa+aaaa+aa...a的值，其中a是一个数字。
	// 例如2+22+222+2222+22222(此时共有5个数相加)，几个数相加由键盘控制。
	@Test
	public void test08() {
		Scanner input = new Scanner(System.in);
		System.out.println("请输入题目中a的数值：");
		int a = input.nextInt();
		System.out.println("请输入共有几个数相加：");
		int i = input.nextInt();
		// 几个数相加的和
		int s = 0;
		// 一个中间数值，默认为1
		int temp = 1;
		// 先输出一个基数
		System.out.print(a);
		// for循环控制中间数的值
		for (int j = 0; j < i; j++) {
			// 如果只有一个数相加，那么中间数为1
			if (j == 0) {
				temp = 1;
				// 如果多个数相加，中间数的值
			} else {
				temp = temp * 10 + 1;
				// 输出每次要加的数
				System.out.print("+" + temp * a);
			}
			// 计算相加的和
			s = s + temp * a;
		}
		System.out.print("=" + s);
	}

	// 【程序9】
	// 题目：一个数如果恰好等于它的因子之和，这个数就称为 "完数 "。例如6=1＋2＋3.编程 找出1000以内的所有完数。
	@Test
	public void test09() {
		System.out.println("1000以内的完数有:");
		// for循环，一次检索1000以内的数是否符合要求
		for (int i = 2; i <= 1000; i++) {
			// 定义变量：表示因数的和
			int sum = 0;
			// 寻找i的因数
			for (int j = 1; j < i; j++) {
				// 如果i可以整除j，j为i的因数
				if (i % j == 0) {
					// 求所有因数的和
					sum = sum + j;
				}
			}
			// 如果一个数等于自己因数的和（不包括自身），则这个数为“完数”，输出
			if (sum == i) {
				System.out.print("  " + i);
			}
		}
	}

	// 【程序10】
	// 题目：一球从100米高度自由落下，每次落地后反跳回原高度的一半，再落下
	// 求它在 第10次落地时，共经过多少米？第10次反弹多高？
	@Test
	public void test10() {
		// 初始高度：100米
		float high = 100;
		// 共经过的距离：初始为0
		float sumhigh = 0;
		// for循环表示10次下落过程
		for (int i = 0; i < 10; i++) {
			sumhigh = sumhigh + high;
			// 每次落地后反跳回原高度的一半
			high = high / 2;
			// 两次sumhigh = sumhigh + high;表示球经过的总距离
			sumhigh = sumhigh + high;
		}
		System.out.print("第10次落地时，共经过" + sumhigh + "米，反弹" + high + "米。");
	}

	// 【程序11】
	// 题目：有1、2、3、4四个数字，能组成多少个互不相同且无重复数字的三位数？都是多少？
	@Test
	public void test11() {
		// 组成的三位数
		int temp = 0;
		// 组成符合要求的三位数的个数
		int z = 0;
		// 百位上的数
		for (int i = 1; i <= 4; i++) {
			// 十位上的数
			for (int j = 1; j <= 4; j++) {
				// 个位上的数
				for (int k = 1; k <= 4; k++) {
					// 互不相同且无重复数字的三位数
					if (i != j && i != k && j != k) {
						// 找到一个就使个数加1
						z++;
						// 百十个位组合成三位数
						temp = i * 100 + j * 10 + k;
						// 打印输出每个三位数
						System.out.println(" " + temp);
					}
				}
			}
		}
		System.out.println("这样的数共有" + z + "个");
	}

	// 【程序12】
	// 题目：企业发放的奖金根据利润提成。
	// 1.利润(I)低于或等于10万元时，奖金可提10%；
	// 2.利润在10万到20万之间时，低于10万元的部分按10%提成，高于10万元的部分，可提成7.5%；
	// 3.20万到40万之间时，高于20万元的部分，可提成5%；
	// 4.40万到60万之间时高于40万元的部分，可提成3%；
	// 5.60万到100万之间时，高于60万元的部分，可提成1.5%，
	// 6.高于100万元时，超过100万元的部分按1%提成，
	// 从键盘输入当月利润，求应发放奖金总数？
	@Test
	public void test12() {
		Scanner input = new Scanner(System.in);
		System.out.println("请输入当月的利润：单位(万元)");
		// 从控制台输入当月利润
		int I = input.nextInt();
		// 利润
		double j = 0;
		// 利润(I)低于或等于10万元时，奖金可提10%；
		if (I <= 10) {
			j = I * 0.1;
			// 利润在10万到20万之间时，低于10万元的部分按10%提成，高于10万元的部分，可提成7.5%
		} else if (I > 10 && I <= 20) {
			j = 10 * 0.1 + (I - 10) * 0.075;
			// 20万到40万之间时，高于20万元的部分，可提成5%
		} else if (I > 20 && I <= 40) {
			j = 10 * 0.1 + (I - 10) * 0.075 + (I - 20) * 0.05;
			// 40万到60万之间时高于40万元的部分，可提成3%
		} else if (I > 40 && I <= 60) {
			j = 10 * 0.1 + (I - 10) * 0.075 + (I - 20) * 0.005 + (I - 40) * 0.03;
			// 60万到100万之间时，高于60万元的部分，可提成1.5%
		} else if (I > 60 && I <= 100) {
			j = 10 * 0.1 + (I - 10) * 0.075 + (I - 20) * 0.005 + (I - 40) * 0.003 + (I - 60) * 0.15;
			// 高于100万元时，超过100万元的部分按1%提成
		} else if (I > 100) {
			j = 10 * 0.1 + (I - 10) * 0.075 + (I - 20) * 0.005 + (I - 40) * 0.003 + (I - 60) * 0.15 + (I - 100) * 0.01;
		}
		System.out.println("当月应发放的奖金总数为：" + j + "万元");
	}

	// 【程序13】
	// 题目：一个整数，它加上100后是一个完全平方数，再加上168又是一个完全平方数，请问该数是多少？
	@Test
	public void test13() {
		// 不知道有这样的数有多少；定义为long型，检索范围之内的所有的数是否符合要求
		for (long i = 0; i < 1000000000; i++) {
			// 加100，再加168，分别对其开方，若结果为整数，则符合要求
			if (Math.sqrt((long) (i + 100)) % 1 == 0 && Math.sqrt((long) (i + 100 + 168)) % 1 == 0) {
				// 打印出符合要求的数
				System.out.println(i);
			}
		}
	}

	// 【程序14】
	// 题目：输入某年某月某日，判断这一天是这一年的第几天？(2016年)
	@Test
	public void test14() {
		Scanner input = new Scanner(System.in);
		// 从控制台依次输入年月日
		System.out.println("请输入年份：");
		int y = input.nextInt();
		System.out.println("请输入月份：");
		int m = input.nextInt();
		System.out.println("请输入日期：");
		int d = input.nextInt();
		// 天数，表示这一年的第几天
		int sum = 0;
		// 闰年标志变量
		int temp = 0;
		// 输入不同的月份，sum不同，此循环中的sum为前m-1个月的总天数
		switch (m) {
		case 1:
			sum = 0;
			break;
		case 2:
			sum = 31;
			break;
		case 3:
			// 默认2月为28天，后边还会判定闰年
			sum = 59;
			break;
		case 4:
			sum = 90;
			break;
		case 5:
			sum = 120;
			break;
		case 6:
			sum = 151;
			break;
		case 7:
			sum = 181;
			break;
		case 8:
			sum = 212;
			break;
		case 9:
			sum = 243;
			break;
		case 10:
			sum = 273;
			break;
		case 11:
			sum = 304;
			break;
		case 12:
			sum = 334;
			break;
		default:
			System.out.println("输入月份错误！请重新输入。");
			break;
		}

		// 判断输入的年份是否是闰年，闰年2月为29天，平年2月为28天
		if (y % 400 == 0 | y % 4 == 0 & y % 100 != 0) {
			temp = 1;
		} else {
			temp = 0;
		}
		// 如果为闰年，且输入月份为3月份以后，sum要加1天。
		if (temp == 1 && m > 2) {
			sum = sum + 1 + d;
		} else {
			sum = sum + d;
		}
		// 输出结果
		System.out.println(y + "年" + m + "月" + d + "日是" + y + "年的第" + sum + "天。");
	}

	// 【程序15】
	// 题目：输入三个整数x,y,z，请把这三个数由小到大输出。
	@Test
	public void test15() {
		// 从控制台输入三个整数值
		Scanner input = new Scanner(System.in);
		System.out.println("请输入整数X：");
		int x = input.nextInt();
		System.out.println("请输入整数Y：");
		int y = input.nextInt();
		System.out.println("请输入整数Z：");
		int z = input.nextInt();
		// 默认x<y<x
		// 如果x>y,交换x,y的值
		if (x > y) {
			int temp = x;
			x = y;
			y = temp;
		}
		// 如果x>z,交换x,z的值
		if (x > z) {
			int temp = x;
			x = z;
			z = temp;
		}
		// 如果y>z,交换y,z的值
		if (y > z) {
			int temp = y;
			y = z;
			z = temp;
		}
		// 输出结果
		System.out.println("三个数从小到大依次是：" + x + " " + y + " " + z);
	}

}
